﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows.Forms;
using yafc.Activity;
using yafc.Data;
using yafc.Interface.Api;

namespace yafc.UI.Components
{
	public partial class SessionView : UserControl
	{
		private Session session;
		private int max = 20;
		private bool sending = false;

		private enum OperationType
		{
			Send,
			Reply,
			Retweet,
		}
		private OperationType opType = OperationType.Send;
		private Post replyTo = Post.Empty;
		
		private OperationType OpType
		{
			get { return opType; }
			set { opType = value; UpdateCaretPos(); }
		}
		public int MaxPost
		{
			get { return max; }
			set { max = value; }
		}

		public SessionView(string name)
		{
			InitializeComponent();

			session = new Session(name);
			session.NewPost += OnNewPost;
			session.LoginResponse += OnLogin;
			session.SendResponse += OnSend;

			list.Comparison = PostItemCompare;
		}

		public void Login(yafc.Interface.IPlugin plugin)
		{
			LoginBox.Instance().ShowDialog(plugin.Name, 
				(Name, Passwd) => Login(plugin.Factory, plugin.Name, Name, Passwd),
				LoginValidator);
		}
		public void Send()
		{
			if (inputBox.Text.Length == 0)
				return;

			if (replyTo != Post.Empty)
			{
				var replyPrefix = "@" + replyTo.post.name + " ";
				if (inputBox.Text.Length > replyPrefix.Length && 
					inputBox.Text.Substring(0, replyPrefix.Length) == replyPrefix)
				{
					session.Reply(inputBox.Text, replyTo);
				}
				else
				{
					session.Send(inputBox.Text);
				}
			}
			else
			{
				session.Send(inputBox.Text);
			}
			sending = true;
			opType = OperationType.Send;
		}

		protected virtual void Login(IFactory f, string Serv, string Uname, string Passwd)
		{
			if (session.Contains(Serv, Uname))
			{
				session.Relogin(Serv, Uname, Passwd);
			}
			else
			{
				session.Login(f, Serv, Uname, Passwd);
			}
		}
		protected virtual bool LoginValidator(string Serv, string Uname, out string Reason)
		{
			Reason = null;
			if (session.Contains(Serv, Uname))
			{
				Reason = "当前会话中已登录了" + Uname + "@" + Serv;
				return false;
			}
			return true;
		}

		private void AddPosts(ICollection<Post> posts)
		{
			foreach (var p in posts)
			{
				var pi = new PostItem(p);
				pi.Reply += OnReply;
				pi.Retweet += OnRetweet;
				list.Add(pi);
			}
			list.PerformLayout();
			list.Invalidate();
		}

		protected virtual void OnNewPost(object sender, NewPostEventArgs e)
		{
			if (e.posts.Count == 0)
				return;

			this.BeginInvoke((MethodInvoker)(() => AddPosts(e.posts)));
		}
		protected virtual void OnLogin(object sender, LoginResults lr)
		{
			MethodInvoker operation;
			switch (lr.status)
			{
			case HttpStatusCode.OK:
				operation = delegate
				{
					LoginBox.Instance().Hide();
				};
				break;

			case HttpStatusCode.Unauthorized:
				operation = delegate
				{
					LoginBox.Instance().LoginFailed("用户名或密码错误");
				};
				break;

			default:
				operation = delegate
				{
					LoginBox.Instance().LoginFailed("网络错误，请重试。");
				};
				break;
			}
			LoginBox.Instance().BeginInvoke(operation);
		}
		protected virtual void OnSend(object sender, SendResults sr)
		{
			switch (sr.status)
			{
			case HttpStatusCode.OK:
				if (sending)
				{
					BeginInvoke((MethodInvoker)(() => inputBox.Clear()));
				}
				break;
			default:
				throw new Exception("Unhandled error in OnSend!");
			}
		}
		protected virtual void OnReply(object sender, EventArgs e)
		{
			var pi = sender as PostItem;
			if (pi == null)
				return;

			replyTo = pi.Post;
			var p = pi.Post;
			inputBox.Clear();
			inputBox.Text = "@" + p.post.name + " ";
			inputBox.Focus();
			OpType = OperationType.Reply;
		}
		protected virtual void OnRetweet(object sender, EventArgs e)
		{
			var pi = sender as PostItem;
			if (pi == null)
				return;

			var p = pi.Post;
			inputBox.Clear();
			inputBox.Text = "RT" + p.post.ToString();
			inputBox.Focus();
			OpType = OperationType.Retweet;
		}

		protected int PostItemCompare(ListBoxItem a, ListBoxItem b)
		{
			var lhs = a as PostItem;
			var rhs = b as PostItem;
			if (lhs.Post.post.timestamp == rhs.Post.post.timestamp)
				return 0;
			else if (lhs.Post.post.timestamp < rhs.Post.post.timestamp)
				return 1;
			else
				return -1;
		}

		private void sendBtn_Click(object sender, EventArgs e)
		{
			Send();
		}
		private void inputBox_Enter(object sender, EventArgs e)
		{
			UpdateCaretPos();
		}
		private void inputBox_TextChanged(object sender, EventArgs e)
		{
			sending = false;
		}
		private void inputBox_MouseEnter(object sender, EventArgs e)
		{
			inputBox.Focus();
		}
		private void inputBox_Leave(object sender, EventArgs e)
		{
			list.Focus();
		}
	
		private void UpdateCaretPos()
		{
			switch (OpType)
			{
			case OperationType.Send:
				inputBox.SelectAll();
				break;

			case OperationType.Reply:
				inputBox.SelectionStart = inputBox.Text.Length;
				inputBox.SelectionLength = 0;
				break;

			case OperationType.Retweet:
				inputBox.SelectionStart = 0;
				inputBox.SelectionLength = 0;
				break;
			}
		}

	}
}
